/**
 * 
 */
package com.facebookfetcher.main;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import net.htmlparser.jericho.Attributes;
import net.htmlparser.jericho.Element;
import net.htmlparser.jericho.HTMLElementName;
import net.htmlparser.jericho.OutputDocument;
import net.htmlparser.jericho.Source;
import net.htmlparser.jericho.TextExtractor;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.facebookdirectory.entity.FBAppInfo;
import com.facebookfetcher.Utlity.GlobalValue;

/**
 * @author piglet
 *
 */
public class FBDataSourceImpl implements FacebookDataSource {
	protected static final Log logger = LogFactory.getLog("FBDataSource");
	private static final String FACEBOOK_URL = "http://www.facebook.com/apps/application.php?id=";	
	private static final String FACEBOOK_SEARCH = "http://www.facebook.com/search.php?q=";
	private static final String[] PAGE_ERROR_TAGS={
		"Profile Unavailable"
	};
	private static final String TITLE = "og:title";
	private static final String OG_URL = "og:url";
	private static final String OG_IMAGE = "og:image";
	private static final String DESCRIPTION = "Description of Application";
	private static final String DEVELOPER = "About the Developer";
	private static final String DEVELOPERNAME = "Developer Name";
	
	/* (non-Javadoc)
	 * @see com.facebookfetcher.main.FacebookDataSource#getAppInfo(java.lang.String)
	 */
	@Override
	public FBAppInfo getAppInfo(String link) {
		FBAppInfo appInfo = null;				
		//TODO: use id
		/*
		 * onloadRegister(function (){JSCC.get('j4e4b4a0505eea2a168042451').init($("contentArea"), $('rightCol'), $('headerArea'), $('toolbarContainer'));});
		 */
		try {
			URL url;
			if(link.contains("?"))
				url = new URL(link+"&sk=info&_fb_noscript=1");
			else
				url = new URL(link+"?sk=info&_fb_noscript=1");
			logger.info("url: "+url);
			//InputStreamReader reader = new InputStreamReader(url.openStream(),"gb2312");
			HttpURLConnection urlc = (HttpURLConnection) url.openConnection();
		    urlc.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; GTB7.1; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; MDDR; .NET4.0C)");
		    urlc.setRequestProperty("Accept", "image/jpeg, application/x-ms-application, image/gif, application/xaml+xml, image/pjpeg, application/x-ms-xbap, */*");
		    urlc.connect();
			InputStreamReader reader = new InputStreamReader(urlc.getInputStream(),"utf-8");
			//InputStreamReader reader = new InputStreamReader(url.openStream(),"utf-8");
			Source source=new Source(reader);
			logger.debug("content:"+source.toString());
			Element header = source.getFirstElement(HTMLElementName.HEAD);
			List<Element> metaList = header.getAllElements(HTMLElementName.META);
			List<Element> linkList = header.getAllElements(HTMLElementName.LINK);
			boolean valid = false;
			String profileName = null;
			String profile_photo_url = null;
			String mainURL = null;
			String appId = null;
			for(Element meta:metaList)
			{
				String property = meta.getAttributeValue("property");
				if(property!=null)
				{					
					if(property.equals(TITLE))
					{
						valid = true;
						profileName = meta.getAttributeValue("content");
					}
					else if(property.equals(OG_URL))
					{
						mainURL = meta.getAttributeValue("content");
					}
					else if(property.equals(OG_IMAGE))
					{
						profile_photo_url = meta.getAttributeValue("content");
					}
				}
			}
			//if(!isValidPage(source))
			if(!valid)
			{
				logger.warn("invalid page:"+link);
				return appInfo;
			}
			for(Element item:linkList)
			{
				Attributes attributes = item.getAttributes();
				if("alternate".equals(attributes.getValue("rel"))&&"application/atom+xml".equals(attributes.getValue("type")))
				{
					String href = attributes.getValue("href");
					String str = href.replace("/feeds/page.php?", "");
					String[] array = str.split("&");
					for(int i=0; i<array.length; i++)
					{
						if(array[i].startsWith("id="))
						{
							appId = array[i].replace("id=", "");
							break;
						}
					}
				}
			}
			//logger.info("content: "+source.toString());
			
			//profile photo
			Element pagelet_profile_picture = source.getElementById("pagelet_profile_picture");
			if(pagelet_profile_picture!=null)
			{
				Element profile_photo = pagelet_profile_picture.getFirstElement(HTMLElementName.IMG);
				profile_photo_url = profile_photo.getAttributeValue("src");
				logger.debug("photo: "+profile_photo_url);
			}
			//average rating			
			Element pagelet_review_summary = source.getElementById("pagelet_review_summary");
			if(pagelet_review_summary==null)
			{
				logger.warn("pagelet_review_summary is null: "+link);
				return null;
			}
			Element average_rating_desc = pagelet_review_summary.getFirstElementByClass("average_rating_desc");
			float average_rating = 0;
			String reviews = null;
			if(average_rating_desc!=null)
			{
				average_rating = parseRating(average_rating_desc.getTextExtractor().toString());
				logger.debug("average rating: "+average_rating);			
				Element aggregate_review_title = pagelet_review_summary.getFirstElementByClass("aggregate_review_title");
				reviews = aggregate_review_title.getTextExtractor().toString();
				logger.debug("reviews: "+reviews);
			}
			//Statistic
			Number monthActive = 0;
			Element pagelet_app_stats = source.getElementById("pagelet_app_stats");
			if(pagelet_app_stats!=null)
			{
				Element uiNumber = pagelet_app_stats.getFirstElementByClass("uiNumberGiant fsxxl fwb");
				if(uiNumber!=null)
				{
					String statistic = uiNumber.getTextExtractor().toString();
					monthActive = NumberFormat.getInstance().parse(statistic);
				}
			}
			logger.debug("monthly active users: "+monthActive);
			
			//Category
			Element pls =pagelet_app_stats.getFirstElementByClass("pls");
			String category = pls.getTextExtractor().toString();
			logger.debug("category:"+category);
			
			//Profile Name
//			Element profileHeader = source.getElementById("pagelet_header");
//			Element ginormousProfileName = profileHeader.getFirstElement(HTMLElementName.H1);
//			//Element ginormousProfileName = profileHeader.getFirstElementByClass("profileName fn ginormousProfileName fwb");
//			String profileName = ginormousProfileName.getTextExtractor().toString();
//			logger.debug("profile name:"+profileName);
			
			//
			Element contentArea = source.getElementById("contentArea");
			Element pagelet_profile_info = contentArea.getFirstElement(HTMLElementName.TABLE);
			List<Element> TRs = pagelet_profile_info.getAllElements(HTMLElementName.TR);
			String description = null;
			String developer = null;
			String developerName = null;
			for(Element item:TRs)
			{
				Element label = item.getFirstElementByClass("label");
				Element data = item.getFirstElementByClass("data");				
				logger.debug(label.getTextExtractor().toString()+":");
				String value = fixFBLink(data);
				String labeltext = new TextExtractor(label).toString();
				if(labeltext.equals(DESCRIPTION))
				{
					description = value;
				}
				else if(labeltext.equals(DEVELOPER))
				{
					developer = value;
				}
				else if(labeltext.equals(DEVELOPERNAME))
				{
					developerName = value;
				}
				logger.debug(value);
			}
			appInfo = new FBAppInfo();
			appInfo.setId(appId);
			appInfo.setAverageRating(average_rating);
			appInfo.setCategory(category);	
			appInfo.setMainURL(mainURL);
			appInfo.setMonthActive(monthActive.longValue());
			appInfo.setProfileName(profileName);
			appInfo.setLanguage(GlobalValue.checkLanguage(profileName));
			appInfo.setProfilePhoto(profile_photo_url);
			appInfo.setReviews(reviews);
			appInfo.setDescription(description);
			appInfo.setDeveloper(developer);
			appInfo.setDeveloperName(developerName);
			//Pictures
//			url = new URL(FACEBOOK_URL+appId+"&sk=wall");
//			reader = new InputStreamReader(url.openStream());
			if(link.contains("?"))
				url = new URL(link+"&sk=wall&_fb_noscript=1");
			else
				url = new URL(link+"?sk=wall&_fb_noscript=1");
			logger.info("url: "+url);					
			urlc = (HttpURLConnection) url.openConnection();
		    urlc.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; GTB7.1; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; MDDR; .NET4.0C)");
		    urlc.setRequestProperty("Accept", "image/jpeg, application/x-ms-application, image/gif, application/xaml+xml, image/pjpeg, application/x-ms-xbap, */*");
		    urlc.connect();
			reader = new InputStreamReader(urlc.getInputStream(),"utf-8");
			source=new Source(reader);
			if(!isValidPage(source))
			{
				logger.warn("invalid page appId:"+appId);				
			}
			//logger.info("content: "+source.toString());
			Element pagelet_photo_bar = source.getElementById("pagelet_photo_bar");
			List<Element> pics = pagelet_photo_bar.getAllElements(HTMLElementName.A);
			List<String> appImages = new ArrayList<String>();
			for(Element pic:pics)
			{
				String content = pic.getAttributeValue("ajaxify");
				String str = URLDecoder.decode(content,"UTF-8");				
				String[] items = str.split("&");
				for(String item:items)
				{
					if(item.startsWith("src="))
					{
						String pic_url = item.replace("src=","");
						logger.debug("pic:"+pic_url);
						appImages.add(pic_url);
						break;
					}
				}
			}
			if(!appImages.isEmpty())
			{
				appInfo.setPics(appImages);
			}
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return appInfo;
	}

	private String fixFBLink(Element data) {
		//logger.info(data.toString());
		List<Element> links = data.getAllElements(HTMLElementName.A);
		OutputDocument output = new OutputDocument(data);
		for(Element link:links)
		{	
			String uri = link.getAttributeValue("href");
			if(uri==null)
			{
				return "";
			}
			try {
				String str = URLDecoder.decode(uri,"UTF-8");				
				String[] array = str.split("&");
				String ref = array[0].replace("/l.php?u=", "");				
				String title = link.getTextExtractor().toString();						
				output.replace(link, "<a href=\""+ref+"\" target=\"_blank\">"+title+"</a>");				
			} catch (UnsupportedEncodingException e) {
				logger.error(e.getMessage());
				e.printStackTrace();				
			}
						
		}
		return output.toString();
	}

	private boolean isValidPage(Source source) {
		String str = source.getTextExtractor().toString();
		if(str==null||str.isEmpty())
		{
			return false;
		}
		for(String errorTag:PAGE_ERROR_TAGS)
		{
			if(str.contains(errorTag))
				return false;
		}
		return true;
	}

	@Override
	public List<String> getFetchLink(List<Request> requestList) {
		List<String> links = new ArrayList<String>();
		for(Request request: requestList)
		{
			switch(request.getType())
			{
			case Name:		
				try {
					URL url = new URL(FACEBOOK_SEARCH+URLEncoder.encode(request.getName(),"UTF-8")+"&type=apps");			
					logger.info("url: "+url);
					InputStreamReader reader = new InputStreamReader(url.openStream(),"utf-8");
					Source source=new Source(reader);					
					logger.debug("content:"+source.toString());
					Element search_results = source.getElementById("pagelet_search_results_0");
					if(search_results!=null)
					{
						List<Element> items = search_results.getAllElements(HTMLElementName.LI);						
						for(int i=0; i<items.size()&&i<10;i++)
						{							
							Element item = items.get(i);
							String link = item.getFirstElement(HTMLElementName.A).getAttributeValue("href");
							links.add(link);
							
//							if(item.getTextExtractor().toString().contains("monthly active users"))
//							{
//								String link = item.getFirstElement(HTMLElementName.A).getAttributeValue("href");
//								links.add(link);
//							}														
						}
					}
					else
					{
						logger.warn("not found pagelet_search_results_0: "+url);
					}
					reader.close();					
				} catch (MalformedURLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (UnsupportedEncodingException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}				
				break;
			case AppId:
				links.add(FACEBOOK_URL+request.getName());
				break;
			}
		}
		return links;
	}
	
	private float parseRating(String rating) {
		float ret = 0;
		if(rating!=null)
		{			
			String str = rating.replace("out of 5)", "").replace("(", "");			
			ret = Float.parseFloat(str)/5;			
		}
		return ret;
	}
}
